package com.common.job;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

import com.alibaba.fastjson.JSON;
import com.common.util.ConstantStock;
import com.common.util.FormatUtil;
import com.common.util.HttpUtil;
import com.demo.common.dto.JuHeDto;
import com.demo.common.dto.JuHeResultDataDto;
import com.demo.common.model.JhStockinfo;
import com.demo.common.model.Stocksignal;
import com.demo.common.model._MappingKit;
import com.jfinal.kit.PropKit;
import com.jfinal.log.Log;
import com.jfinal.plugin.activerecord.ActiveRecordPlugin;
import com.jfinal.plugin.druid.DruidPlugin;

public class GetStockInfoJob implements Job {

	private static final Log log = Log.getLog(GetStockInfoJob.class);

	@Override
	public void execute(JobExecutionContext job) throws JobExecutionException {
		/*
		 * List<Stockinfo> stockinfoList = new ArrayList<Stockinfo>();
		 * List<Stocksignal> stocksignalList = new ArrayList<Stocksignal>();
		 * List<Stock> stockList = Stock.dao.findAll(); String[] stockcodes =
		 * new String[10]; for (int i = 0; i < stockList.size(); i++) {
		 * stockcodes[i%10] = stockList.get(i).getStockCode(); if(i > 0 && i %
		 * 10 == 0) { HttpUtil.getStockInfoList(stockcodes, stockinfoList,
		 * stocksignalList); } } Stockinfo.dao.batchSave(stockinfoList);
		 * Stocksignal.dao.batchSave(stocksignalList);
		 */
		// 1.获取股票数据
		getStockInfoFromJuHe("http://web.juhe.cn:8080/finance/stock/shall");
		getStockInfoFromJuHe("http://web.juhe.cn:8080/finance/stock/szall");
		// 2.分析是否有交易信号
		checkSignal();
		// 3.判断是否打架
		checkIsFight();
		// 4.判断今天的交易信号是否有左耳
		checkIsLeftEye();
		// 5.判断昨天的交易信号是否有右耳
		checkIsRightEye();
	}

	private void getStockInfoFromJuHe(String url) {
		log.error("开始任务定时下载股票信息的任务!");
		List<Integer> szErrorPageList = new ArrayList<Integer>();
		// 获取深圳股票页数
		int szCount = getStockCount(url);
		int szPage = 0;
		List<JhStockinfo> infoList = new ArrayList<JhStockinfo>();
		if (szCount % 80 == 0) {
			szPage = szCount / 80;
		} else {
			szPage = szCount / 80 + 1;
		}

		// 向聚合接口获取数据
		for (int i = 1; i <= szPage; i++) {
			JuHeDto juHeDto = getJuHeDto(url, i, 4);
			if (juHeDto == null) {
				szErrorPageList.add(i);
			} else {
				for (JuHeResultDataDto dto : juHeDto.getResult().getData()) {
					infoList.add(Dto2Model(dto));
				}
			}
		}

		log.error("开始处理错误列表中的数据，错误列表剩余[" + szErrorPageList.size() + "]个");
		// 处理请求失败的页面
		while (szErrorPageList.size() > 0) {
			Iterator<Integer> iterator = szErrorPageList.iterator();
			while (iterator.hasNext()) {
				int page = iterator.next();
				JuHeDto juHeDto = getJuHeDto(url, page, 4);
				if (juHeDto != null) {
					for (JuHeResultDataDto dto : juHeDto.getResult().getData()) {
						infoList.add(Dto2Model(dto));
					}
					iterator.remove();
				}
				log.error("错误列表剩余[" + szErrorPageList.size() + "]个");
			}
		}
		JhStockinfo.dao.batchSave(infoList);
		log.error("下载股票完毕!共" + szCount + "条");
	}

	private int getStockCount(String url) {
		JuHeDto juHeDto = getJuHeDto(url, 1, 1);
		if (juHeDto != null) {
			return juHeDto.getResult().getTotalCount();
		}
		return 0;
	}

	private static JhStockinfo Dto2Model(JuHeResultDataDto dto) {
		JhStockinfo info = new JhStockinfo();
		info.setAmount(dto.getAmount());
		info.setBuy(dto.getBuy());
		info.setChangepercent(dto.getChangepercent());
		info.setHigh(dto.getHigh());
		info.setLow(dto.getLow());
		info.setName(dto.getName());
		info.setOpen(dto.getOpen());
		info.setPricechange(dto.getPricechange());
		info.setSell(dto.getSell());
		info.setSettlement(dto.getSettlement());
		info.setSymbol(dto.getSymbol());
		info.setTicktime(dto.getTicktime());
		info.setTrade(dto.getTrade());
		info.setVolume(dto.getVolume());
		info.setCode(dto.getCode());
		info.setCreatetime(FormatUtil.formatDate(new Date(), "yyyy-MM-dd"));
		return info;
	}

	/**
	 * 
	 * @param url
	 * @param page
	 * @param type
	 * @return
	 */
	private JuHeDto getJuHeDto(String url, int page, int type) {
		for (int i = 0; i < PropKit.getInt("retryNum"); i++) {
			try {
				String jsonStr = HttpUtil.getStockInfoFromJuHe(url, PropKit.get("juheApiKey"), page, type, 300, 300);
				JuHeDto juHeDto = JSON.parseObject(jsonStr, JuHeDto.class);
				if (0 != juHeDto.getError_code()) {
					throw new RuntimeException("从聚合上获取数据失败!错误编码:" + juHeDto.getError_code());
				} else {
					return juHeDto;
				}
			} catch (Exception e) {
				log.error("第[" + (i + 1) + "]次获取第[" + page + "]页股票数据失败:" + e.getMessage());
				try {
					Thread.sleep(300);
				} catch (InterruptedException e1) {
					e1.printStackTrace();
				}
			}
		}
		return null;
	}

	/**
	 * 获取交易信号
	 */
	private void checkSignal() {
		log.error("开始检查交易信号------------");
		List<JhStockinfo> infoList = JhStockinfo.dao.findByCreatetime(FormatUtil.formatDate(new Date(), "yyyy-MM-dd"));
		List<Stocksignal> signalList = new ArrayList<Stocksignal>();
		for (JhStockinfo stockinfo : infoList) {
			BigDecimal settlement = stockinfo.getSettlement(); // 昨收
			BigDecimal open = stockinfo.getOpen(); // 开盘价
			BigDecimal high = stockinfo.getHigh(); // 最高价
			BigDecimal low = stockinfo.getLow(); // 最低价
			BigDecimal trade = stockinfo.getTrade(); // 今收

			if (settlement.compareTo(new BigDecimal(0)) > 0 && open.compareTo(new BigDecimal(0)) > 0
					&& high.compareTo(new BigDecimal(0)) > 0 && low.compareTo(new BigDecimal(0)) > 0
					&& trade.compareTo(new BigDecimal(0)) > 0) {

				// 1 获取振幅
				BigDecimal amplitude = high.subtract(low).divide(settlement, 2);
				// 2 振幅大于设定值
				if (amplitude
						.compareTo(BigDecimal.valueOf(Double.valueOf(PropKit.get(ConstantStock.MIN_AMPLITUDE)))) >= 0) {
					// 3 判断是否为信号
					BigDecimal wava = high.subtract(low)
							.multiply(BigDecimal.valueOf(Double.valueOf(PropKit.get(ConstantStock.MAX_WAVA))));
					BigDecimal up_wava = high.subtract(wava);
					BigDecimal down_wava = low.add(wava);

					Stocksignal stocksignal = new Stocksignal();
					stocksignal.setSignalDate(stockinfo.getCreatetime());
					stocksignal.setStockCode(stockinfo.getCode());
					stocksignal.setWeight(amplitude);
					stocksignal.setSymbol(stockinfo.getSymbol());

					if (open.compareTo(up_wava) >= 0 && trade.compareTo(up_wava) >= 0) {// 3.1
																						// 如果开盘价和收盘价都在最高价和最低价三分之一以上的位置则为买入信号
						stocksignal.setSignalType(Stocksignal.TYPE_BUY);
						signalList.add(stocksignal);
					} else if (open.compareTo(down_wava) <= 0 && trade.compareTo(down_wava) <= 0) {// 3.2
																									// 如果开盘价和收盘价都在最高价和最低价三分之一以下的位置则为卖出信号
						stocksignal.setSignalType(Stocksignal.TYPE_SELL);
						signalList.add(stocksignal);
					}
				}
			}

			/**
			 * BigDecimal weight = height.subtract(low).divide(settlement, 2);
			 * if(weight.compareTo(new
			 * BigDecimal(PropKit.get(ConstantStock.MIN_AMPLITUDE))) >= 0) {
			 * BigDecimal lower = trade; BigDecimal heigher = open;
			 * if(trade.compareTo(open) > 0) { lower = open; heigher = trade; }
			 * 
			 * Stocksignal stocksignal = new Stocksignal();
			 * stocksignal.setSignalDate(stockinfo.getCreatetime());
			 * stocksignal.setStockCode(stockinfo.getCode());
			 * stocksignal.setWeight(weight);
			 * stocksignal.setSymbol(stockinfo.getSymbol());
			 * 
			 * BigDecimal tmp = (height.multiply(new
			 * BigDecimal(0.56))).add(low.multiply(new BigDecimal(0.44)));
			 * BigDecimal tmp2 = (height.multiply(new
			 * BigDecimal(0.44))).add(low.multiply(new BigDecimal(0.56)));
			 * if(lower.compareTo((height.multiply(tmp))) > 0) {
			 * stocksignal.setSignalType(Stocksignal.TYPE_BUY);
			 * signalList.add(stocksignal); } else if
			 * (heigher.compareTo((height.multiply(tmp2))) < 0) {
			 * stocksignal.setSignalType(Stocksignal.TYPE_SELL);
			 * signalList.add(stocksignal); } }
			 */

			/*
			 * BigDecimal openningPrice = stockinfo.getOpen(); BigDecimal
			 * currentPrice = stockinfo.getTrade(); BigDecimal hPrice =
			 * stockinfo.getHigh(); BigDecimal lPrice = stockinfo.getLow();
			 * if(openningPrice.compareTo(new BigDecimal(0)) > 0 &&
			 * currentPrice.compareTo(new BigDecimal(0)) > 0 &&
			 * hPrice.compareTo(new BigDecimal(0)) > 0 && lPrice.compareTo(new
			 * BigDecimal(0)) > 0) {
			 * 
			 * //判断是否有交易信号 BigDecimal x = hPrice.subtract(lPrice);
			 * if(x.compareTo(new BigDecimal(0)) > 0) { BigDecimal st =
			 * openningPrice.subtract(currentPrice).abs(); BigDecimal _H;
			 * BigDecimal _L; if(st.multiply(new BigDecimal(5)).compareTo(x) <=
			 * 0) { Stocksignal stocksignal = new Stocksignal();
			 * stocksignal.setSignalDate(stockinfo.getCreatetime());
			 * stocksignal.setStockCode(stockinfo.getCode()); BigDecimal weight
			 * = new BigDecimal(0); if(openningPrice.compareTo(currentPrice) >
			 * 0) { _H = openningPrice; _L = currentPrice; } else { _H =
			 * currentPrice; _L = openningPrice; } BigDecimal y =
			 * hPrice.subtract(_H);//上影线 BigDecimal z =
			 * _L.subtract(lPrice);//下影线 if(z.divide(x, 2).compareTo(new
			 * BigDecimal(0.75)) >= 0) { weight = z.divide(x, 2);
			 * stocksignal.setSignalType(Stocksignal.TYPE_BUY); } else if
			 * (y.divide(x, 2).compareTo(new BigDecimal(0.75)) > 0) { weight =
			 * y.divide(x, 2); stocksignal.setSignalType(Stocksignal.TYPE_SELL);
			 * } else { continue; } stocksignal.setWeight(weight);
			 * stocksignal.setSymbol(stockinfo.getSymbol());
			 * signalList.add(stocksignal); } } }
			 */
		}
		// 开始保存交易信号
		for (Stocksignal stocksignal : signalList) {
			Stocksignal tmp = Stocksignal.dao.findBySymbol(stocksignal.getSymbol());
			if (tmp == null) {
				stocksignal.save();
			} else {
				tmp.setSignalDate(FormatUtil.formatDate(new Date()));
				tmp.update();
			}
		}
		log.error("交易信号检查完毕------------");
	}

	/**
	 * 检查是否有左耳
	 */
	public void checkIsLeftEye() {
		// 获取今天所有的交易信号
		List<Stocksignal> signalList = Stocksignal.dao.findListByDate(FormatUtil.formatDate(new Date()), 1);
		for (Stocksignal stocksignal : signalList) {
			// 判断是否是星期一
			Calendar cal = Calendar.getInstance();
			cal.setTime(new Date());
			// 如果是星期一，则获取上个星期五的数据进行判断
			if (cal.get(Calendar.DAY_OF_WEEK) == Calendar.MONDAY) {
				cal.add(Calendar.DATE, -3);
			}
			JhStockinfo _info = JhStockinfo.dao.findByTimeAndCode(FormatUtil.formatDate(cal.getTime(), "yyyy-MM-dd"),
					stocksignal.getStockCode());
			if (_info != null) {
				JhStockinfo info = JhStockinfo.dao.findByTimeAndCode(FormatUtil.formatDate(new Date(), "yyyy-MM-dd"),
						stocksignal.getStockCode());
				if (_info.getHigh().compareTo(info.getHigh()) > 0) {
					if (info.getOpen().compareTo(info.getTrade()) > 0) {
						if (info.getTrade().compareTo(_info.getLow()) > 0) {
							stocksignal.setIsLeftEye(1);
							stocksignal.update();
						}
					} else {
						if (info.getOpen().compareTo(_info.getLow()) > 0) {
							stocksignal.setIsLeftEye(1);
							stocksignal.update();
						}
					}
				}
			}
		}
	}

	/**
	 * 检查是否有右耳
	 */
	public void checkIsRightEye() {
		// 判断是否是星期一
		Calendar cal = Calendar.getInstance();
		cal.setTime(new Date());
		// 如果是星期一，则获取上个星期五的数据进行判断
		if (cal.get(Calendar.DAY_OF_WEEK) == Calendar.MONDAY) {
			cal.add(Calendar.DATE, -3);
		} else {
			cal.add(Calendar.DATE, -1);
		}
		// 获取上个交易日的交易信号
		List<Stocksignal> signalList = Stocksignal.dao.findListByDate(FormatUtil.formatDate(cal.getTime()), 1);
		for (Stocksignal stocksignal : signalList) {
			JhStockinfo _info = JhStockinfo.dao.findByTimeAndCode(FormatUtil.formatDate(cal.getTime(), "yyyy-MM-dd"),
					stocksignal.getStockCode());// 上个交易日的日线
			JhStockinfo info = JhStockinfo.dao.findByTimeAndCode(FormatUtil.formatDate(new Date(), "yyyy-MM-dd"),
					stocksignal.getStockCode());// 当前交易日的日线
			if (info.getHigh().compareTo(_info.getHigh()) > 0) {
				if (_info.getOpen().compareTo(_info.getTrade()) > 0) {
					if (info.getLow().compareTo(_info.getTrade()) < 0) {
						stocksignal.setIsRightEye(1);
						stocksignal.update();
					}
				} else {
					if (info.getLow().compareTo(_info.getOpen()) < 0) {
						stocksignal.setIsRightEye(1);
						stocksignal.update();
					}
				}
			}
		}
	}

	/**
	 * 判断是否打架
	 */
	public void checkIsFight() {
		// 判断是否是星期一
		Calendar cal = Calendar.getInstance();
		cal.setTime(new Date());
		// 如果是星期一，则获取上个星期五的数据进行判断
		if (cal.get(Calendar.DAY_OF_WEEK) == Calendar.MONDAY) {
			cal.add(Calendar.DATE, -3);
		} else {
			cal.add(Calendar.DATE, -1);
		}
		// 获取今天所有的交易信号
		List<Stocksignal> signalList = Stocksignal.dao.findListByDate(FormatUtil.formatDate(new Date()), 1);
		for (Stocksignal stocksignal : signalList) {
			// 获取上个交易日的信号
			Stocksignal tmp = Stocksignal.dao.findByDateAndCode(FormatUtil.formatDate(cal.getTime(), "yyyy-MM-dd"),
					stocksignal.getStockCode(), 2);
			if (tmp != null) {
				stocksignal.setIsFight(1);
				stocksignal.update();
			}
		}
	}

	public static void main(String[] args) {
		System.out.println("-----------开始任务");
		PropKit.use("a_little_config.txt");
		DruidPlugin dp = new DruidPlugin(
				"jdbc:mysql://127.0.0.1/jfinal_stock?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull", "root",
				"root");
		ActiveRecordPlugin arp = new ActiveRecordPlugin(dp);
		_MappingKit.mapping(arp);
		// 与web环境唯一的不同是要手动调用一次相关插件的start()方法
		dp.start();
		arp.start();
		// new GetStockInfoJob().checkSignal();
		try {
			new GetStockInfoJob().execute(null);
		} catch (JobExecutionException e) {
			e.printStackTrace();
		}
		System.out.println("-----------结束任务");
		/*
		 * List<String[]> testList = new ArrayList<String[]>(); testList.add(new
		 * String[]{"1","1","1"}); testList.add(new String[]{"2","2","2"});
		 * testList.add(new String[]{"3","3","3"}); testList.add(new
		 * String[]{"4","4","4"}); Iterator<String[]> iters =
		 * testList.iterator(); while(iters.hasNext()) { String[] strs =
		 * iters.next(); if(strs[0].equals("2")) { iters.remove(); } } for
		 * (String[] strings : testList) { System.out.println(strings[0]); }
		 */

		// System.out.println(new
		// GetStockInfoJob().getStockCount("http://web.juhe.cn:8080/finance/stock/szall"));
		/*
		 * Calendar cl = Calendar.getInstance(); cl.setTime(new Date());
		 * System.out.println(FormatUtil.formatDate(cl.getTime()));
		 * cl.add(Calendar.DATE, -3);
		 * System.out.println(FormatUtil.formatDate(cl.getTime()));
		 */
	}

}
